from __future__ import annotations

from typing import Optional, List
import random

from .generator_base import BaseQuestionGenerator
from .models import KnowledgePoint, GenerationConfig, Question
from .templates import cognitive_cue


class RuleBasedQuestionGenerator(BaseQuestionGenerator):
    def generate_one(
        self,
        knowledge_point: KnowledgePoint,
        config: GenerationConfig,
        random_state: Optional[random.Random] = None,
    ) -> Question:
        rng = random_state or random
        difficulty = _blend_difficulty(knowledge_point.difficulty_level, config.normalized_difficulty())
        cue = cognitive_cue(knowledge_point.cognitive_level)

        if config.question_type == "选择题":
            options_count = max(3, min(6, config.format_spec.options_count))
            stem = f"关于{knowledge_point.name}，下列说法中最{cue}的是："
            correct, distractors = _make_choice_options(knowledge_point, cue, options_count, rng)
            options = [correct] + distractors
            rng.shuffle(options)
            correct_index = options.index(correct)
            correct_answer = chr(ord('A') + correct_index)
            explanation = (
                f"依据知识点描述：{knowledge_point.description}。"
                if config.format_spec.include_explanation else None
            )
            return Question(
                id=Question.new_id(),
                type="选择题",
                stem=stem,
                options=options,
                correct_answer=correct_answer,
                explanation=explanation,
                difficulty=difficulty,
                cognitive_level=knowledge_point.cognitive_level,
                knowledge_points=[knowledge_point.name],
            )

        if config.question_type == "填空题":
            stem = f"请填空：与{knowledge_point.name}相关的{cue}是______。"
            answer = _generate_short_answer(knowledge_point, cue)
            explanation = answer if config.format_spec.include_explanation else None
            return Question(
                id=Question.new_id(),
                type="填空题",
                stem=stem,
                options=None,
                correct_answer=answer,
                explanation=explanation,
                difficulty=difficulty,
                cognitive_level=knowledge_point.cognitive_level,
                knowledge_points=[knowledge_point.name],
            )

        if config.question_type == "判断题":
            statement_true = _make_true_statement(knowledge_point)
            statement_false = _make_false_statement(knowledge_point)
            statement = statement_true if rng.random() < 0.5 else statement_false
            correct = "正确" if statement == statement_true else "错误"
            stem = f"判断正误：{statement}。"
            explanation = (
                f"根据知识点：{knowledge_point.description}"
                if config.format_spec.include_explanation else None
            )
            return Question(
                id=Question.new_id(),
                type="判断题",
                stem=stem,
                options=["正确", "错误"],
                correct_answer=correct,
                explanation=explanation,
                difficulty=difficulty,
                cognitive_level=knowledge_point.cognitive_level,
                knowledge_points=[knowledge_point.name],
            )

        if config.question_type == "计算题":
            context = _make_numeric_context(knowledge_point, rng, difficulty)
            stem = f"已知{context}，请{cue}{knowledge_point.name}并给出结果。"
            answer = _compute_answer_from_context(context)
            explanation = (
                f"步骤：基于{knowledge_point.name}的计算规则进行求解。"
                if config.format_spec.include_explanation else None
            )
            return Question(
                id=Question.new_id(),
                type="计算题",
                stem=stem,
                options=None,
                correct_answer=answer,
                explanation=explanation,
                difficulty=difficulty,
                cognitive_level=knowledge_point.cognitive_level,
                knowledge_points=[knowledge_point.name],
            )

        # 解答题 (开放式)
        stem = f"请{cue}{knowledge_point.name}：结合题意，阐述关键步骤与理由。"
        explanation = (
            f"参考：结合法条/公式/原理对{knowledge_point.name}进行阐述。"
            if config.format_spec.include_explanation else None
        )
        return Question(
            id=Question.new_id(),
            type="解答题",
            stem=stem,
            options=None,
            correct_answer=None,
            explanation=explanation,
            difficulty=difficulty,
            cognitive_level=knowledge_point.cognitive_level,
            knowledge_points=[knowledge_point.name],
        )


def _blend_difficulty(kp_diff: int, cfg_diff: int) -> int:
    return max(1, min(10, round(0.6 * kp_diff + 0.4 * cfg_diff)))


def _make_choice_options(kp: KnowledgePoint, cue: str, n: int, rng: random.Random) -> tuple[str, List[str]]:
    correct = f"与{kp.name}{cue}直接相关的表述"
    pool = [
        f"与{kp.name}边缘相关但不充分的表述",
        f"与{kp.name}无关或概念混淆的表述",
        f"与{kp.name}相近概念的表述",
        f"表述过于宽泛，无法支撑{cue}",
        f"遗漏关键条件的{kp.name}表述",
    ]
    rng.shuffle(pool)
    distractors = pool[: max(0, n - 1)]
    return correct, distractors


def _generate_short_answer(kp: KnowledgePoint, cue: str) -> str:
    return f"{kp.name}-{cue}要点"


def _make_true_statement(kp: KnowledgePoint) -> str:
    return f"{kp.name}的核心性质与描述相符"


def _make_false_statement(kp: KnowledgePoint) -> str:
    return f"{kp.name}与常见误解等同"


def _make_numeric_context(kp: KnowledgePoint, rng: random.Random, difficulty: int) -> str:
    a = rng.randint(1, 9 + difficulty)
    b = rng.randint(1, 9 + difficulty)
    return f"a={a}, b={b}, 需要基于{kp.name}进行运算"


def _compute_answer_from_context(context: str) -> str:
    # 占位实现：真实实现应解析 context
    return "结果取决于具体计算规则"